﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using NAudio.Wave;
using VocabLib;
using VocabUtils;

namespace VocabGUI
{
	/// <summary>
	/// Interaction logic for MainWindow.xaml
	/// </summary>
	public partial class MainWindow : Window
	{
		private VocabModel model;
		private const string xmlPath = "ser.xml";
		private ViewModel viewModel;
		private VocabModel.Record currentQuestion;

		public MainWindow()
		{
			InitializeComponent();
			this.loadVocabPathTextBox.Text = @"F:\Download\Dropbox\Angol\koviszotar-merge.csv";
			this.exportToCsvPathTextBox.Text = @"koviszotar-export.csv";
			model = new VocabModel();
			model.LoadFromFile(xmlPath);
			this.viewModel = new ViewModel();
			this.DataContext = this.viewModel;
			this.hunWordTextBox.IsEnabled = false;

			this.RefreshViewModel();

			this.PutNextQuestion();
		}

		private string GetCambridgeLink(string word)
		{
			return "http://dictionary.cambridge.org/search/american-english/direct/?q=" + WordUtils.TrimPrepositions(word);
		}

		private string GetSongUrlOnPage(string pageUrl)
		{
			WebClient client = new WebClient();
			try
			{
				string webPage = client.DownloadString(pageUrl);
				Regex regex = new Regex("data-src-mp3=\"([^\"]+)\"");
				//Regex isAmericanRegex = new Regex( "listen to American pronunciation" );
				Regex isBritishRegex = new Regex("listen to British English pronunciation");
				var matches = regex.Matches(webPage);
				if (matches.Count > 0)
				{
					if (matches.Count > 1 && isBritishRegex.IsMatch(webPage))
						return matches[1].Groups[1].Value;
					else
						return matches[0].Groups[1].Value;
				}
				else
				{
					return null;
				}
			}
			catch (WebException)
			{
				return null;
			}
		}

		private string TryGetSongAndPageUrl(string word)
		{
			var pageUrl = GetCambridgeLink(word);
			var songUrl = GetSongUrlOnPage(pageUrl);

			return songUrl;
		}

		private void RefreshViewModel()
		{
			this.viewModel.LearnedWordCount = this.model.Vocabulary.LearnedWordCount;
			this.viewModel.NotKnownWordCount = this.model.Vocabulary.NotKnownWordCount;
			this.viewModel.PositiveCoveragePercent = this.model.Vocabulary.PositiveCoverage * 100;
			this.viewModel.TotalWordPairCount = this.model.Vocabulary.TotalWordPairCount;
		}

		private void PutNextQuestion()
		{
			this.currentQuestion = this.model.GetNextQuestion();
			this.engWordTextBox.Text = "";

			if (this.currentQuestion == null)
				return;

			this.hunWordTextBox.Text = this.currentQuestion.Hun;
		}

		private void loadVocabButton_Click(object sender, RoutedEventArgs e)
		{
			this.model.MergeDictionary(this.loadVocabPathTextBox.Text);
			this.RefreshViewModel();
			this.PutNextQuestion();
		}

		private void clearButton_Click(object sender, RoutedEventArgs e)
		{
			MessageBoxResult key = MessageBox.Show(
				"Are you sure you want to clear the statistics?",
				"Confirm",
				MessageBoxButton.YesNo,
				MessageBoxImage.Question,
				MessageBoxResult.No);
			if (key == MessageBoxResult.No)
			{
				return;
			}
			this.model.Vocabulary.ClearUsages();
		}

		private void submitButton_Click(object sender, RoutedEventArgs e)
		{
			if (this.currentQuestion == null)
				return;

			string answerText = this.engWordTextBox.Text;
			bool isCorrect = this.currentQuestion.Guess(answerText);
			var word = this.currentQuestion.Eng;
			var songUrl = TryGetSongAndPageUrl(word);
			var validPage = songUrl != null;

			this.viewModel.AddAnswer(answerText, this.currentQuestion, isCorrect, validPage);
			this.RefreshViewModel();

			if (validPage)
			{
				new Thread(() =>
											{
												try
												{
													var client = new WebClient();
													var song = client.DownloadData(songUrl);

													AutoResetEvent signal = new AutoResetEvent(false);

													using (var ms = new MemoryStream(song))
													using (var rdr = new Mp3FileReader(ms))
													using (var wavStream = WaveFormatConversionStream.CreatePcmStream(rdr))
													using (var baStream = new BlockAlignReductionStream(wavStream))
													using (var waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()))
													{
														waveOut.Init(baStream);
														waveOut.Play();
														waveOut.PlaybackStopped += (o, args) =>
														{
															signal.Set();
														};
														signal.WaitOne();
													}
												}
												catch (Exception)
												{
												}
											}).Start();
			}

			this.PutNextQuestion();
		}

		private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
		{
			try
			{
				model.SaveToFile(xmlPath);
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.ToString());
			}
		}

		private void engWordTextBox_KeyDown(object sender, KeyEventArgs e)
		{
			if (e.Key == Key.Enter)
			{
				submitButton_Click(sender, null);
			}
		}

		private void cambridgeitButton_Click(object sender, RoutedEventArgs e)
		{
			Button button = sender as Button;
			VocabGUI.ViewModel.Answer answer = button.DataContext as VocabGUI.ViewModel.Answer;

			var songUrl = TryGetSongAndPageUrl(answer.EngCorrect);
			if (songUrl == null)
				return;

			Process.Start(new ProcessStartInfo(GetCambridgeLink(answer.EngCorrect)));
		}

		private void worstWordsButton_Click(object sender, RoutedEventArgs e)
		{
			new WordsWindow(new WordsWindowViewModel(this.model.Vocabulary.WorstWords)).ShowDialog();
		}

		private void notKnownWordsButton_Click(object sender, RoutedEventArgs e)
		{
			new WordsWindow(new WordsWindowViewModel(this.model.Vocabulary.NotKnownWords)).ShowDialog();
		}

		private void correctButton_Click(object sender, RoutedEventArgs e)
		{
			Button button = sender as Button;
			VocabGUI.ViewModel.Answer answer = button.DataContext as VocabGUI.ViewModel.Answer;

			CorrectViewModel cvm = new CorrectViewModel
															 {
																 Eng = answer.EngCorrect,
																 Hun = answer.Hun
															 };
			new CorrectWindow(cvm).ShowDialog();

			// Refresh the model according to the corrected record
			this.model.Vocabulary.RefreshRecord(answer.Hun, cvm.Hun, cvm.Eng);
		}

		private void exportToCsvButton_Click(object sender, RoutedEventArgs e)
		{
			this.model.SaveToCsv(this.exportToCsvPathTextBox.Text);
		}
	}
}
